/*
 * OperationalSemanticsChooser.h
 *
 *  Created on: Oct 29, 2012
 *      Author: raul
 */

#ifndef OPERATIONALSEMANTICSCHOOSER_H_
#define OPERATIONALSEMANTICSCHOOSER_H_

#define MAX_NEW_NODES 100

#include "SyntacticTreeLibrary.h"
#include "HashTableLTS.h"

typedef struct {
        int numOfStates;
        stateLTS obtainedStates[MAX_NEW_NODES];
} processingOutput;

int oS_deterministicStability(Node *tree) {
        int result = 1;
        int type = sT_getType(tree);
//        printf("[%p,%p]\n",tree->left,tree->right);
        if (type == IN_CHO) {
                return 0;
        }

        if (type == PREFIX || type == SEQ_PROC) {
                if (tree->left) {
                        result *= oS_deterministicStability(tree->left);
                }
        }

        if (type == EXT_CHO || type == PARALLEL || type == PR_CHO) {
                if (tree->left) {
                        result *= oS_deterministicStability(tree->left);
                }
                if (tree->right) {
                        result *= oS_deterministicStability(tree->right);
                }
        }

        return result;
}

int oS_action(Node *tree) {
        int result = 1;

        int type = sT_getType(tree);

        if (type == PR_CHO) {
                return 0;
        }

        if (type == PREFIX || type == SEQ_PROC) {
                if (tree->left) {
                        result *= oS_deterministicStability(tree->left);
                }
        }

        if (type == EXT_CHO || type == PARALLEL) {
                if (tree->left) {
                        result *= oS_deterministicStability(tree->left);
                }
                if (tree->right) {
                        result *= oS_deterministicStability(tree->right);
                }
        }

        return result;
}

void oS_processingNode(stateLTS *LTSnode, processingOutput *result) {

        result->numOfStates = 0;

        Node *node = LTSnode->node;

//First of all, we must know if the process is deterministically stable
        if (!oS_deterministicStability(node)) {
//                printf("This node is NOT deterministically stable\n");
                solvingInternalChoice(LTSnode, node, NULL, LTSnode->id, result);
        } else {
//                printf("This node is deterministically stable\n");

//Now let's check if the can evolvo through action rules
                if (!oS_action(node)) {
//                      printf("This node contains probabilistic behaviours \n");
                        solvingProbabilisticChoice(LTSnode, node, NULL, LTSnode->id,
                                        result);

                } else {
//                      printf("This node doesn't contain probabilistic behaviours \n");
                }

        }

}

void solvingInternalChoice(stateLTS *LTSnode, Node *tree, char *appliedRule,
                char *LTSStateKey, processingOutput *result) {

//      Node *tree = LTSnode->node;
        if (tree) {
                int type = sT_getType(tree);

                if (appliedRule == NULL) {
                        appliedRule = (char *) malloc(sizeof(char) * MAX_RULE_LENGHT);
                        if (type == IN_CHO) {
                                appliedRule = "ND-Def";
                        }
                        if (type == EXT_CHO) {
                                appliedRule = "ND-Ext";
                        }
                        if (type == PR_CHO) {
                                appliedRule = "ND-Pro";
                        }
                        if (type == PARALLEL) {
                                appliedRule = "ND-Par";
                        }

                }

                if (sT_isOperator(type) /*&& result->numOfStates < 4*/) {
                        if (type == IN_CHO) {
                                Node *father = sT_getFatherNode(LTSnode->node, tree->key);

                                //If the internal choice is located at the root node

                                stateLTS *son1 = (stateLTS *) malloc(sizeof(stateLTS));
                                stateLTS *son2 = (stateLTS *) malloc(sizeof(stateLTS));

                                son1->numberOfTransitions = 0;
                                son2->numberOfTransitions = 0;

//                              son1->node = (Node *) malloc(sizeof(Node));
//                              son2->node = (Node *) malloc(sizeof(Node));

                                if (father == NULL) {
                                        son1->node = sT_getSubTree(tree->left, son1->node, "0");
                                        son2->node = sT_getSubTree(tree->right, son2->node, "0");

                                } else {
                                        //It copies the whole binary tree structure
                                        son1->node = sT_getSubTree(LTSnode->node, son1->node, "0");
                                        son2->node = sT_getSubTree(LTSnode->node, son2->node, "0");

                                        Node *leftSon = (Node *) malloc(sizeof(Node));
                                        Node *rightSon = (Node *) malloc(sizeof(Node));

                                        char *fatherKey = (char *) malloc(
                                                        sizeof(char) * MAX_ID_LENGHT);
                                        strcpy(fatherKey, father->key);

                                        char *treeKey = (char *) malloc(
                                                        sizeof(char) * MAX_ID_LENGHT);
                                        strcpy(treeKey, tree->key);

                                        leftSon = (Node *) tree->left;
                                        rightSon = (Node *) tree->right;

                                        char *leftKey = (char *) malloc(
                                                        sizeof(char) * MAX_ID_LENGHT);
                                        strcpy(leftKey, leftSon->key);

                                        char *rightKey = (char *) malloc(
                                                        sizeof(char) * MAX_ID_LENGHT);
                                        strcpy(rightKey, rightSon->key);

                                        sT_replacingNode(son1->node, fatherKey, treeKey, leftKey);
//                                      printf("Son1: ");sT_printout(son1->node);printf("\n");
                                        sT_replacingNode(son2->node, fatherKey, treeKey, rightKey);
//                                      printf("Son2: ");sT_printout(son2->node);printf("\n");
                                }

                                char *newKey1 = (char *) malloc(
                                                sizeof(char) * MAX_LTSNODE_ID_LENGHT);
                                char *newKey2 = (char *) malloc(
                                                sizeof(char) * MAX_LTSNODE_ID_LENGHT);

                                strcpy(newKey1, LTSStateKey);
                                strcpy(newKey2, LTSStateKey);

                                char tempNumber[2];
                                sprintf(tempNumber, "%d", result->numOfStates);
                                /*son1->id = */strcat(newKey1, tempNumber);
//                              son1->id = (char *)malloc(sizeof(char)*strlen(newKey1));
                                strcpy(son1->id,newKey1);


                                result->obtainedStates[result->numOfStates] = *son1;
                                result->numOfStates++;

//                              tempNumber[0] = ' ';
//                              tempNumber[1] = ' ';
                                sprintf(tempNumber, "%d", result->numOfStates);
                                /*son2->id = */strcat(newKey2, tempNumber);
//                              son2->id = (char *)malloc(sizeof(char)*strlen(newKey2));
                                strcpy(son2->id,newKey2);

                                result->obtainedStates[result->numOfStates] = *son2;
                                result->numOfStates++;

                                transitionLTS *transition1 = (transitionLTS *) malloc(
                                                sizeof(transitionLTS));
                                transitionLTS *transition2 = (transitionLTS *) malloc(
                                                sizeof(transitionLTS));

                                int lengthAppliedRule = strlen(appliedRule);

//                              transition1->rule = (char *) malloc(
//                                              sizeof(char) * lengthAppliedRule);
//                              transition2->rule = (char *) malloc(
//                                              sizeof(char) * lengthAppliedRule);

                                strcpy(transition1->rule, appliedRule);
                                strcpy(transition2->rule, appliedRule);

                                int lengthSubStateId = (strlen(LTSStateKey) + 2);

//                              transition1->subState = (char *) malloc(
//                                              sizeof(char) * lengthSubStateId);
//                              transition2->subState = (char *) malloc(
//                                              sizeof(char) * lengthSubStateId);

                                strcpy(transition1->subState, newKey1);
                                strcpy(transition2->subState, newKey2);

                                LTSnode->subStates[LTSnode->numberOfTransitions] = *transition1;
                                LTSnode->numberOfTransitions++;
                                LTSnode->subStates[LTSnode->numberOfTransitions] = *transition2;
                                LTSnode->numberOfTransitions++;
                                return;

                        } else {
                                //If the internal choice is not located as a root node
                                solvingInternalChoice(LTSnode, tree->left, appliedRule,
                                                LTSStateKey, result);
                                solvingInternalChoice(LTSnode, tree->right, appliedRule,
                                                LTSStateKey, result);
                        }
                }
        }
}

void solvingProbabilisticChoice(stateLTS *LTSnode, Node *tree,
                char *appliedRule, char *LTSStateKey, processingOutput *result) {

        int type = sT_getType(tree);
        if (sT_isOperator(type)) {
                if (type == PR_CHO) {

                }
        }

}

#endif /* OPERATIONALSEMANTICSCHOOSER_H_ */
